package com.shell.customer.group.service.impl;

import com.shell.bee.acct.account.po.AcctBas;
import com.shell.bee.acct.account.po.AcctBkp;
import com.shell.bee.acct.transaction.po.AcctTxRec;
import com.shell.bee.base.utils.SpringContextUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.contract.ContService;
import com.shell.bee.contract.po.ContBas;
import com.shell.bee.persistence.annotation.Pagination;
import com.shell.bee.persistence.model.PageLimit;
import com.shell.bee.persistence.service.impl.PersistentServiceImpl;
import com.shell.constant.rel.AssetCode;
import com.shell.customer.base.dao.CusGrpDao;
import com.shell.customer.base.service.CusTagRecService;
import com.shell.customer.base.service.CusTagService;
import com.shell.customer.base.service.CustomerService;
import com.shell.customer.chain.callback.service.CustChainCallbackService;
import com.shell.customer.group.service.CusGrpService;
import com.shell.customer.group.vo.Group;
import com.shell.customer.po.CusGrp;
import com.shell.customer.po.CusRec;
import com.shell.customer.po.CusTag;
import com.shell.customer.po.CusTagRec;
import com.shell.customer.trade.service.CustomerAcctService;
import com.shell.customer.trade.service.TradeService;
import com.shell.framework.utils.SysDateUtil;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("cusGrpService")
public class CusGrpServiceImpl extends PersistentServiceImpl<CusGrp> implements CusGrpService {
	@Autowired
	private CusGrpDao cusGrpDao;
	@Autowired
	private CustomerService customerService;
	@Autowired
	private CustomerAcctService customerAcctService;
	@Autowired
	private ContService contService;
	@Autowired
	private TradeService tradeService;
	@Autowired
	private CusTagRecService cusTagRecService;
	@Autowired
	private CusTagService cusTagService;
	@Autowired
	private CustChainCallbackService custChainCallbackService;

	public String createGroup(Group group) {
		String msg = checkCreateGroup(group);
		if (msg != null) {
			return msg;
		}
		String grpId = SystemUtil.getUUID();
		CusGrp grp = new CusGrp();
		BeanUtils.copyProperties(group, grp);
		grp.setGrpId(grpId);
		save(grp);

		group.setGrpId(grpId);
		updateCusGrp(group, true);
		saveGroupRel(group, true);
		return null;
	}

	private void updateCusGrp(Group group, boolean create) {
		String grpId = group.getGrpId();
		String grpName = group.getGrpName();

		Set<String> cusIds = new HashSet();
		if (StringUtil.notEmpty(group.getFocalId())) {
			cusIds.add(group.getFocalId());
		}
		cusIds.addAll(group.getFinBuyers());
		cusIds.addAll(group.getFinSellers());
		cusIds.addAll(group.getAdminIds());
		if (("0".equals(group.getConfirmerType())) && (StringUtil.notEmpty(group.getConfirmerId()))) {
			cusIds.add(group.getConfirmerId());
		}
		cusIds.add(group.getFirstTrialId());
		cusIds.add(group.getLastTrialId());
		for (String cusId : cusIds) {
			CusRec cus = (CusRec) this.customerService.selectByKey(cusId);
			if (StringUtil.emptyAndNull(cus.getGrpId())) {
				cus.setGrpId(grpId);
				cus.setGrpName(grpName);
				this.customerService.updateNotNull(cus);
			}
		}
		String relTypes;
		List<CusGrp> grps;
		if (!create) {
			Object oriCusIds = new HashSet();
			((Set) oriCusIds).add(findGroupEnt(grpId, "FOCAL_CO"));
			((Set) oriCusIds).addAll(findGroupEntIds(grpId, "FIN_BUYER"));
			((Set) oriCusIds).addAll(findGroupEntIds(grpId, "FIN_SELLER"));
			((Set) oriCusIds).addAll(findGroupEntIds(grpId, "GROUP_ADMIN"));
			((Set) oriCusIds).add(findGroupEnt(grpId, "CONFIRMER"));
			((Set) oriCusIds).add(findGroupEnt(grpId, "GROUP_FIRST_TRIAL"));
			((Set) oriCusIds).add(findGroupEnt(grpId, "GROUP_LAST_TRIAL"));

			StringBuilder relTypesBuilder = new StringBuilder();
			relTypesBuilder.append("FOCAL_CO").append(",");
			relTypesBuilder.append("FIN_BUYER").append(",");
			relTypesBuilder.append("FIN_BUYER").append(",");
			relTypesBuilder.append("GROUP_ADMIN").append(",");
			relTypesBuilder.append("CONFIRMER").append(",");
			relTypesBuilder.append("GROUP_FIRST_TRIAL").append(",");
			relTypesBuilder.append("GROUP_LAST_TRIAL");
			relTypes = relTypesBuilder.toString();
			grps = null;
			for (String cusId : (Set<String>) oriCusIds) {
				if ((cusId != null) && (!cusIds.contains(cusId))) {
					grps = selectCusGroupByTagCode(cusId, relTypes);
					String otherGrpId = null;
					String otherGrpName = null;
					if ((grps != null) && (grps.size() > 0)) {
						for (CusGrp grp : grps) {
							if (!grp.getGrpId().equals(grpId)) {
								otherGrpId = grp.getGrpId();
								otherGrpName = grp.getGrpName();
								break;
							}
						}
					}
					CusRec cus = (CusRec) this.customerService.selectByKey(cusId);
					cus.setGrpId(otherGrpId);
					cus.setGrpName(otherGrpName);
					this.customerService.updateNotNull(cus);
				}
			}
		}
	}

	private void saveGroupRel(Group group, boolean create) {
		String grpId = group.getGrpId();
		String[] delTagCodes = { "FOCAL_CO", "GROUP_ADMIN", "GROUP_FIRST_TRIAL", "GROUP_LAST_TRIAL", "FIN_BUYER",
				"FIN_SELLER", "CONFIRMER" };

		Set<String> cusIds = new HashSet();

		List<String> delCusIds = this.cusTagRecService.deleteCusRecTag(null, grpId, String.join(",", delTagCodes));
		if (StringUtil.notEmpty(group.getFocalId())) {
			this.cusTagRecService.saveCusRecTag(group.getFocalId(), grpId, "FOCAL_CO");
			cusIds.add(group.getFocalId());
		}
		this.cusTagRecService.saveCusRecTag(group.getFirstTrialId(), grpId, "GROUP_FIRST_TRIAL");
		cusIds.add(group.getFirstTrialId());

		this.cusTagRecService.saveCusRecTag(group.getLastTrialId(), grpId, "GROUP_LAST_TRIAL");
		cusIds.add(group.getLastTrialId());
		if (StringUtil.notEmpty(group.getConfirmerId())) {
			this.cusTagRecService.saveCusRecTag(group.getConfirmerId(), grpId, "CONFIRMER");
		}
		for (String adminId : group.getAdminIds()) {
			this.cusTagRecService.saveCusRecTag(adminId, grpId, "GROUP_ADMIN");
			cusIds.add(adminId);
		}
		for (String finBuyerId : group.getFinBuyers()) {
			this.cusTagRecService.saveCusRecTag(finBuyerId, grpId, "FIN_BUYER");
			cusIds.add(finBuyerId);
		}
		for (String finSellerId : group.getFinSellers()) {
			this.cusTagRecService.saveCusRecTag(finSellerId, grpId, "FIN_SELLER");
			cusIds.add(finSellerId);
		}
		cusIds.addAll(delCusIds);
		this.cusTagRecService.syncCusBizBatch(String.join(",", cusIds));
	}

	public String modifyGroup(Group group) {
		String msg = checkModifyGroup(group);
		if (msg != null) {
			return msg;
		}
		CusGrp grp = new CusGrp();
		BeanUtils.copyProperties(group, grp);
		updateNotNull(grp);

		deleteCancelFinBuyersCredit(group);
		updateCusGrp(group, false);
		saveGroupRel(group, false);
		return null;
	}

	private void deleteCancelFinBuyersCredit(Group group) {
		final String grpId = group.getGrpId();
		List<String> oriFinBuyers = findGroupEntIds(grpId, "FIN_BUYER");
		List<String> cancelFinBuyers = group.getCancelFinBuyers();
		if ((cancelFinBuyers != null) && (cancelFinBuyers.size() > 0)) {
			for (String finId : cancelFinBuyers) {
				if (oriFinBuyers.contains(finId)) {
					final List<ContBas> conts = this.contService.selectConts(finId, "40", "6");
					new Thread(new Runnable() {
						public void run() {
							for (ContBas cont : conts) {
								AcctBkp acctBkp = CusGrpServiceImpl.this.customerAcctService
										.getAcctBkp(cont.getBizId());
								if (grpId.equals(acctBkp.getBkpPrdCode())) {
									AcctTxRec acctTxRec = CusGrpServiceImpl.this.getTrdAssetTxRec(cont, acctBkp);
									Map<String, String> ret = CusGrpServiceImpl.this.tradeService.fire(acctTxRec);
									CusGrpServiceImpl.this.custChainCallbackService.callback(acctTxRec,
											(String) ret.get("tx_sn"));
								}
							}
						}
					})

							.start();
				}
			}
		}
	}

	private AcctTxRec getTrdAssetTxRec(ContBas cont, AcctBkp acctBkp) {
		AcctTxRec txRec = new AcctTxRec();
		txRec.setTxId(SystemUtil.getUUID());
		txRec.setTxSn(SystemUtil.getUUID());
		txRec.setBizId(acctBkp.getBkpId());
		txRec.setCurrCode(AssetCode.XQT.name());
		txRec.setTxChnCode("C");
		txRec.setOptType("qt_red");
		txRec.setTxType("cc_fin_buy");

		AcctBas txAcct = this.customerAcctService.getAcctBas(acctBkp.getAcctNo());
		txRec.setTxAcctNo(txAcct.getAcctNo());
		txRec.setTxAcctNm(txAcct.getAcctNm());
		txRec.setTxBankNm(txAcct.getFiNm());
		txRec.setTxBkpId(acctBkp.getBkpId());
		txRec.setTxAmt(acctBkp.getAcctAmt());
		txRec.setTxDt(SysDateUtil.getSystemDate());
		txRec.setTxTs(SysDateUtil.getSystemDateTime());
		txRec.setTxAbs("��������");

		txRec.setTxSts("I");

		AcctBas cpAcct = this.customerAcctService.getAcctBas(cont.getSponsor(), "1", null);
		AcctBkp cpBkp = this.customerAcctService.getAcctBkp(cpAcct.getAcctNo(), AssetCode.XQT.name());
		txRec.setCpAcctNo(cpAcct.getAcctNo());
		txRec.setCpAcctNm(cpAcct.getAcctNm());
		txRec.setCpBankNm(cpAcct.getFiNm());
		txRec.setCpBkpId(cpBkp.getBkpId());

		txRec.setTxCashFlag("N");
		txRec.setTxReqFiCls("1");

		String sourceCode = SpringContextUtil.getProperty("system.code");
		txRec.setSrcCode(sourceCode);

		txRec.setDataScLvl("B");

		txRec.setTxPassword(txAcct.getAcctKey());
		return txRec;
	}

	private String checkCreateGroup(Group group) {
		if (StringUtil.emptyAndNull(group.getGrpCode())) {
			return "������������";
		}
		if (StringUtil.emptyAndNull(group.getGrpName())) {
			return "������������";
		}
		if ((group.getFinBuyers() == null) || (group.getFinBuyers().size() == 0)) {
			return "��������������";
		}
		if ((group.getFinSellers() == null) || (group.getFinSellers().size() == 0)) {
			return "��������������";
		}
		if (StringUtil.emptyAndNull(group.getFirstTrialId())) {
			return "����������������";
		}
		if (StringUtil.emptyAndNull(group.getFirstTrialId())) {
			return "����������������";
		}
		if ((group.getAdminIds() == null) || (group.getAdminIds().size() == 0)) {
			return "������������������";
		}
		if (("0".equals(group.getConfirmerType())) && (StringUtil.emptyAndNull(group.getConfirmerId()))) {
			return "��������������";
		}
		return null;
	}

	private String checkModifyGroup(Group group) {
		if (StringUtil.emptyAndNull(group.getGrpId())) {
			return "��id������";
		}
		String msg = checkCreateGroup(group);
		if (msg != null) {
			return msg;
		}
		return msg;
	}

	public void deleteGroup(String... grpIds) {
		for (String grpId : grpIds) {
			delete(grpId);
		}
	}

	@Pagination
	public List<Group> queryGroups(PageLimit limit, Group group) {
		group.setSearchStr(StringUtil.getParameterLike(group.getSearchStr()));

		List<Group> groups = this.cusGrpDao.queryGroups(group);
		for (Group grp : groups) {
			queryGroupRoles(grp, "FIN_BUYER");
			queryGroupRoles(grp, "FIN_SELLER");
			queryGroupRoles(grp, "GROUP_ADMIN");
			queryGroupRoles(grp, "CONFIRMER");
			queryGroupRoles(grp, "GROUP_FIRST_TRIAL");
			queryGroupRoles(grp, "GROUP_LAST_TRIAL");
			queryGroupRoles(grp, "FOCAL_CO");
		}
		return groups;
	}

	public int save(CusGrp entity) {
		return super.save(entity);
	}

	public CusGrp selectByCode(String grpCode) {
		CusGrp grp = new CusGrp();
		grp.setGrpCode(grpCode);
		return (CusGrp) selectOne(grp);
	}

	public CusGrp selectByName(String grpName) {
		CusGrp grp = new CusGrp();
		grp.setGrpName(grpName);
		return (CusGrp) selectOne(grp);
	}

	private void queryGroupRoles(Group group, String tagCode) {
		List<CusRec> finners = this.customerService.selectCusByGroupIdAndTagCode(group.getGrpId(), tagCode);
		if ((finners != null) && (finners.size() > 0)) {
			StringBuilder builder = new StringBuilder();
			List<String> rolerIds = new ArrayList();
			for (Iterator localIterator = finners.iterator(); localIterator.hasNext();) {
				CusRec cusRec = (CusRec) localIterator.next();
				builder.append(cusRec.getCusName()).append(",");
				rolerIds.add(cusRec.getCusId());
			}
			String rolersStr = builder.substring(0, builder.length() - 1);
			switch (tagCode) {
			case "FIN_BUYER":
				group.setFinBuyers(rolerIds);
				group.setFinBuyersStr(rolersStr);
				break;
			case "FIN_SELLER":
				group.setFinSellers(rolerIds);
				group.setFinSellersStr(rolersStr);
				break;
			case "GROUP_ADMIN":
				group.setAdminIds(rolerIds);
				group.setAdminNames(rolersStr);
				break;
			case "CONFIRMER":
				group.setConfirmerId((String) rolerIds.get(0));
				group.setConfirmerName(rolersStr);
				break;
			case "GROUP_FIRST_TRIAL":
				group.setFirstTrialId((String) rolerIds.get(0));
				group.setFirstTrialName(rolersStr);
				break;
			case "GROUP_LAST_TRIAL":
				group.setLastTrialId((String) rolerIds.get(0));
				group.setLastTrialName(rolersStr);
				break;
			case "FOCAL_CO":
				group.setFocalId((String) rolerIds.get(0));
				group.setFocalName(rolersStr);
				break;
			}
		}
	}

	public String findGroupEnt(String grpId, String tagCode) {
		CusTag tag = new CusTag();
		tag.setTagCode(tagCode);
		tag = (CusTag) this.cusTagService.selectOne(tag);

		CusTagRec tagRec = new CusTagRec();
		tagRec.setGrpId(grpId);
		tagRec.setTagId(tag.getTagId());
		tagRec = (CusTagRec) this.cusTagRecService.selectOne(tagRec);
		if (tagRec == null) {
			return null;
		}
		return tagRec.getCusId();
	}

	public List<CusRec> findGroupEnts(String grpId, String tagCode) {
		String[] tagCodes = null;
		if (StringUtil.notEmpty(tagCode)) {
			tagCodes = tagCode.split(",");
		}
		return this.cusGrpDao.findGroupEnts(grpId, tagCodes);
	}

	public List<String> findGroupEntIds(String grpId, String tagCode) {
		String[] tagCodes = { tagCode };
		List<CusRec> recs = this.cusGrpDao.findGroupEnts(grpId, tagCodes);
		List<String> cusIds = new ArrayList();
		for (CusRec rec : recs) {
			cusIds.add(rec.getCusId());
		}
		return cusIds;
	}

	public List<CusGrp> selectCusGroupByTagCode(String cusId, String tagCodes) {
		String[] tagCodeArr = StringUtil.emptyAndNull(tagCodes) ? null : tagCodes.split(",");
		return this.cusGrpDao.selectCusGroupByTagCode(cusId, tagCodeArr);
	}

	public boolean validateGroupBuyerFinner(String grpId, String finId) {
		boolean ret = true;
		List<String> oriFinBuyers = findGroupEntIds(grpId, "FIN_BUYER");
		AcctBkp acctBkp;
		if (oriFinBuyers.contains(finId)) {
			List<ContBas> conts = this.contService.selectConts(finId, "40", "6");
			acctBkp = null;
			for (ContBas cont : conts) {
				acctBkp = this.customerAcctService.getAcctBkp(cont.getBizId());
				if (acctBkp.getAcctAmt().compareTo(acctBkp.getAcctBlc()) == 1) {
					ret = false;
				}
			}
		}
		return ret;
	}
}
